/**
 * @copyright Copyright (c) .
 */
// https://github.com/qin-6/lightweight_excel
// Created by Yap Chun Wei
// Version 1.0 (20 April 2006)
// Version 1.1 (22 April 2006)
// - Fixed bugs with compound files not being able to write files more than 65535 bytes.
// - Fixed bugs with reading and writing to Excel files containing many strings.
// Version 1.2 (30 April 2006)
// - Added operator<< to pass BasicExcelCell to an output stream.
// - Added Print() to BasicExcelWorksheet to print the worksheet to an output stream.
// - Change BasicExcelCell Get functions to const functions.
// - Rename BasicExcelWorksheet functions RenameWorkSheet() to Rename().
// Version 1.3 (10 May 2006)
// - Fixed bugs with reading from Excel files containing Asian characters.
// Version 1.4 (13 May 2006)
// - Fixed bugs with reading and writing to Excel files containing many strings.
// Version 1.5 (15 May 2006)
// - Remove code for ExtSST because it was causing problems with reading and writing
// to Excel files containing many strings.
// Version 1.6 (16 May 2006)
// - Optimized code for reading and writing.
// Version 1.7 (22 May 2006)
// - Fixed code to remove some warnings.
// - Fixed bug with BasicExcelWorksheet::Cell.
// - Fixed bug with BasicExcel::UpdateWorksheets().
// Version 1.8 (23 May 2006)
// - Fixed bug with reading Excel files containing many unicode strings.
// - Fixed code to remove some warnings.
// - Fixed variable code_ duplication in BoolErr.
// - Minor changes to BasicExcelCell:Set functions.
// Version 1.9 (24 May 2006)
// - Changed name_ in Style from SmallString to LargeString.
// - Fixed bug in BasicExcelCell::GetString and BasicExcelCell::GetWString.
// - Minor changes to functions in BasicExcel and BasicExcelWorksheet which checks for unicode.
// - Minor change to SmallString::Read.
// Version 1.10 (30 May 2006)
// - Fixed bug with reading Excel files containing many strings.
// - Remove memory leaks.
// Version 1.11 (2 June 2006)
// - Fixed bug with reading and writing Excel files containing many unicode and ANSI strings.
// Version 1.12 (6 June 2006)
// - Fixed bug with reading and writing Excel files containing many unicode and ANSI strings.
// Version 1.13 (1 August 2006)
// - Changed BasicExcelCell::Get() so that it will get a stored double as an integer or vice versa if necessary.
// - Changed BasicExcelCell::Get() so that it will not cause any errors if a string is empty.
// - Changed BasicExcelCell::SetString() and BasicExcelCell::SetWString() so that it will not save an empty string.
// Version 1.14 (6 August 2006)
// - Fixed bug with reading Excel files that contain a null string.

#ifndef HARDWARE_HI3519CAM_POWERCTL_BASICEXCEL_HPP_
#define HARDWARE_HI3519CAM_POWERCTL_BASICEXCEL_HPP_

#include <algorithm>
#include <cmath>
#include <functional>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <map>
#include <vector>
#include <cstring>

using namespace std;	// NOLINT

#define UTF16
#ifdef UTF16
#define SIZEOFWCHAR_T 2
#else
#define SIZEOFWCHAR_T sizeof(wchar_t)
#endif

namespace YCompoundFiles {
    class Block {	// NOLINT
    // PURPOSE: In charge of handling blocks of data from a file
    public:		// NOLINT
        Block();

        // File handling functions
        bool Create(const wchar_t *filename);
        bool Open(const wchar_t *filename, ios_base::openmode mode = ios_base::in | ios_base::out);
        bool Close();
        bool IsOpen();

        // Block handling functions
        bool Read(size_t index, char *block);
        bool Write(size_t index, const char *block);
        bool Swap(size_t index1, size_t index2);
        bool Move(size_t from, size_t to);
        bool Insert(size_t index, const char *block);
        bool Erase(size_t index);
        bool Erase(vector<size_t> &indices);	// NOLINT

        // Misc functions
        size_t GetBlockSize() const { return blockSize_; }
        void SetBlockSize(size_t size) {
            blockSize_ = size;
            indexEnd_ = fileSize_ / blockSize_ + (fileSize_ % blockSize_ ? 1 : 0);
        }

    protected:				// NOLINT
        vector<char> filename_;
        ios_base::openmode mode_;
        fstream file_;
        size_t blockSize_;
        size_t indexEnd_;
        size_t fileSize_;
    };

    struct LittleEndian {		// NOLINT
        template <typename Type>
        static void Read(const char *buffer, Type &retVal, int pos = 0, int bytes = 0) {	// NOLINT
            retVal = Type(0);
            if (bytes == 0)
                bytes = sizeof(Type);
            for (size_t i = 0; i < bytes; ++i) {
                retVal |= ((Type)((unsigned char)buffer[pos + i])) << 8 * i;
            }
        }

        template <typename Type>
        static void ReadString(const char *buffer, Type *str, int pos = 0, int bytes = 0) {
            for (size_t i = 0; i < bytes; ++i)
                Read(buffer, str[i], pos + i * sizeof(Type));
        }

        template <typename Type>
        static void Write(char *buffer, Type val, int pos = 0, int bytes = 0) {
            if (bytes == 0)
                bytes = sizeof(Type);
            for (size_t i = 0; i < bytes; ++i) {
                buffer[pos + i] = (unsigned char)val;
                val >>= 8;
            }
        }

        template <typename Type>
        static void WriteString(char *buffer, Type *str, int pos = 0, int bytes = 0) {
            for (size_t i = 0; i < bytes; ++i)
                Write(buffer, str[i], pos + i * sizeof(Type));
        }

        template <typename Type>
        static void Read(const vector<char> &buffer, Type &retVal, int pos = 0, int bytes = 0) {	// NOLINT
            retVal = Type(0);
            if (bytes == 0)
                bytes = sizeof(Type);
            for (size_t i = 0; i < bytes; ++i) {
                retVal |= ((Type)((unsigned char)buffer[pos + i])) << 8 * i;
            }
        }

        template <typename Type>
        static void ReadString(const vector<char> &buffer, Type *str, int pos = 0, int bytes = 0) {
            for (size_t i = 0; i < bytes; ++i)
                Read(buffer, str[i], pos + i * sizeof(Type));
        }

        template <typename Type>
        static void Write(vector<char> &buffer, Type val, int pos = 0, int bytes = 0) {		// NOLINT
            if (bytes == 0)
                bytes = sizeof(Type);
            for (size_t i = 0; i < bytes; ++i) {
                buffer[pos + i] = (unsigned char)val;
                val >>= 8;
            }
        }

        template <typename Type>
        static void WriteString(vector<char> &buffer, Type *str, int pos = 0, int bytes = 0) {	// NOLINT
            for (size_t i = 0; i < bytes; ++i)
                Write(buffer, str[i], pos + i * sizeof(Type));
        }

        static void Read(const char *buffer, wchar_t &retVal, int pos = 0, int bytes = 0) {	// NOLINT
            retVal = wchar_t(0);
            if (bytes == 0)
                bytes = SIZEOFWCHAR_T;
            for (int i = 0; i < bytes; ++i) {
                retVal |= ((wchar_t)((unsigned char)buffer[pos + i])) << 8 * i;
            }
        }

        static void ReadString(const char *buffer, wchar_t *str, int pos = 0, int bytes = 0) {
            for (int i = 0; i < bytes; ++i)
                Read(buffer, str[i], pos + i * SIZEOFWCHAR_T);
        }

        static void Write(char *buffer, wchar_t val, int pos = 0, int bytes = 0) {
            if (bytes == 0)
                bytes = SIZEOFWCHAR_T;
            for (int i = 0; i < bytes; ++i) {
                buffer[pos + i] = (unsigned char)val;
                val >>= 8;
            }
        }

        static void WriteString(char *buffer, wchar_t *str, int pos = 0, int bytes = 0) {
            for (int i = 0; i < bytes; ++i)
                Write(buffer, str[i], pos + i * SIZEOFWCHAR_T);
        }

        static void Read(const vector<char> &buffer, wchar_t &retVal, int pos = 0, int bytes = 0) {	// NOLINT
            retVal = wchar_t(0);
            if (bytes == 0)
                bytes = SIZEOFWCHAR_T;
            for (int i = 0; i < bytes; ++i) {
                retVal |= ((wchar_t)((unsigned char)buffer[pos + i])) << 8 * i;
            }
        }

        static void ReadString(const vector<char> &buffer, wchar_t *str, int pos = 0, int bytes = 0) {
            for (int i = 0; i < bytes; ++i)
                Read(buffer, str[i], pos + i * SIZEOFWCHAR_T);
        }

        static void Write(vector<char> &buffer, wchar_t val, int pos = 0, int bytes = 0) {	// NOLINT
            if (bytes == 0)
                bytes = SIZEOFWCHAR_T;
            for (int i = 0; i < bytes; ++i) {
                buffer[pos + i] = (unsigned char)val;
                val >>= 8;
            }
        }

        static void WriteString(vector<char> &buffer, wchar_t *str, int pos = 0, int bytes = 0) {	// NOLINT
            for (int i = 0; i < bytes; ++i)
                Write(buffer, str[i], pos + i * SIZEOFWCHAR_T);
        }
    };

    class CompoundFile {	// NOLINT
    public:			// NOLINT
        enum {
            DUPLICATE_PROPERTY = -6,
            NAME_TOO_LONG = -5,
            FILE_NOT_FOUND = -4,
            DIRECTORY_NOT_EMPTY = -3,
            DIRECTORY_NOT_FOUND = -2,
            INVALID_PATH = -1,
            SUCCESS = 1
        };

        CompoundFile();
        ~CompoundFile();

        // User accessible functions
    public:     // NOLINT
        // Compound File functions
        bool Create(const wchar_t *filename);
        bool Open(const wchar_t *filename, ios_base::openmode mode = ios_base::in | ios_base::out);
        bool Close();
        bool IsOpen();

        // Directory functions
        int ChangeDirectory(const wchar_t *path);
        int MakeDirectory(const wchar_t *path);
        int PresentWorkingDirectory(wchar_t *path);
        int PresentWorkingDirectory(vector<wchar_t> &path); // NOLINT
        int RemoveDirectory(const wchar_t *path);
        int DelTree(const wchar_t *path);
        int DirectoryList(vector<vector<wchar_t>> &list, const wchar_t *path = 0);  // NOLINT

        // File functions
        int MakeFile(const wchar_t *path);
        int RemoveFile(const wchar_t *path);
        int FileSize(const wchar_t *path, size_t &size);            // NOLINT
        int ReadFile(const wchar_t *path, char *data);
        int ReadFile(const wchar_t *path, vector<char> &data);      // NOLINT
        int WriteFile(const wchar_t *path, const char *data, size_t size);
        int WriteFile(const wchar_t *path, const vector<char> &data, size_t size);

        // ANSI char functions
        bool Create(const char *filename);
        bool Open(const char *filename, ios_base::openmode mode = ios_base::in | ios_base::out);
        int ChangeDirectory(const char *path);
        int MakeDirectory(const char *path);
        int PresentWorkingDirectory(char *path);
        int PresentWorkingDirectory(vector<char> &path);        // NOLINT
        int RemoveDirectory(const char *path);
        int DelTree(const char *path);
        int MakeFile(const char *path);
        int RemoveFile(const char *path);
        int FileSize(const char *path, size_t &size);           // NOLINT
        int ReadFile(const char *path, char *data);
        int ReadFile(const char *path, vector<char> &data);     // NOLINT
        int WriteFile(const char *path, char *data, size_t size);
        int WriteFile(const char *path, vector<char> &data, size_t size);       // NOLINT

        // Protected functions and data members
    protected:      // NOLINT
        // General functions and data members
        void IncreaseLocationReferences(vector<size_t> indices);
        void DecreaseLocationReferences(vector<size_t> indices);
        void SplitPath(const wchar_t *path, wchar_t *&parentpath, wchar_t *&propertyname);  // NOLINT
        vector<char> block_;
        Block file_;

        // Header related functions and data members
        bool LoadHeader();
        void SaveHeader();
        class Header {
        public:     // NOLINT
            Header();
            void Write(char *block);
            void Read(char *block);

            long long fileType_;     // Magic number identifying this as a compound file system (0x0000)    // NOLINT
            int uk1_;                 // Unknown constant (0x0008)
            int uk2_;                 // Unknown constant (0x000C)
            int uk3_;                 // Unknown constant (0x0010)
            int uk4_;                 // Unknown constant (0x0014)
            short uk5_;                 // Unknown constant (revision?) (0x0018)        // NOLINT
            short uk6_;                 // Unknown constant    (version?) (0x001A)      // NOLINT
            short uk7_;                 // Unknown constant (0x001C)                    // NOLINT
            short log2BigBlockSize_;    // Log, base 2, of the big block size (0x001E)     // NOLINT
            int log2SmallBlockSize_;    // Log, base 2, of the small block size (0x0020)   // NOLINT
            int uk8_;                 // Unknown constant (0x0024)
            int uk9_;                 // Unknown constant (0x0028)
            int BATCount_;             // Number of elements in the BAT array (0x002C)
            int propertiesStart_;     // Block index of the first block of the property table (0x0030)
            int uk10_;                 // Unknown constant (0x0034)
            int uk11_;                 // Unknown constant (0x0038)
            int SBATStart_;
            int SBATCount_;             // Number of big blocks holding the SBAT (0x0040)
            int XBATStart_;
            int XBATCount_;
            int BATArray_[109];

            size_t bigBlockSize_;
            size_t smallBlockSize_;

        private:        // NOLINT
            void Initialize();
        };
        Header header_;

        // BAT related functions and data members
        void LoadBAT();
        void SaveBAT();
        size_t DataSize(size_t startIndex, bool isBig);
        size_t ReadData(size_t startIndex, char *data, bool isBig);
        size_t WriteData(const char *data, size_t size, int startIndex, bool isBig);
        void GetBlockIndices(size_t startIndex, vector<size_t> &indices, bool isBig);   // NOLINT
        size_t GetFreeBlockIndex(bool isBig);
        void ExpandBATArray(bool isBig);
        void LinkBlocks(size_t from, size_t to, bool isBig);
        void FreeBlocks(vector<size_t> &indices, bool isBig);   // NOLINT
        vector<int> blocksIndices_;
        vector<int> sblocksIndices_;

        // Properties related functions and data members
        class Property {
        public:     // NOLINT
            Property();
            void Write(char *block);
            void Read(char *block);
            friend bool operator==(const CompoundFile::Property &lhs, const CompoundFile::Property &rhs) {
                return (!wcscmp(lhs.name_, rhs.name_));
            }
            friend bool operator<(const CompoundFile::Property &lhs, const CompoundFile::Property &rhs) {
                size_t maxLen1 = wcslen(lhs.name_);
                size_t maxLen2 = wcslen(rhs.name_);
                if (maxLen1 < maxLen2)
                    return true;
                else if (maxLen1 > maxLen2)
                    return false;
                else {          // NOLINT
                    int result = wcscmp(lhs.name_, rhs.name_);
                    if (result <= 0)
                        return true;
                    else
                        return false;
                }
            }
            friend bool operator!=(const CompoundFile::Property &lhs, const CompoundFile::Property &rhs) {
                return !(lhs == rhs);
            }
            friend bool operator>(const CompoundFile::Property &lhs, const CompoundFile::Property &rhs) {
                return (rhs < lhs);
            }
            friend bool operator<=(const CompoundFile::Property &lhs, const CompoundFile::Property &rhs) {
                return !(rhs < lhs);
            }
            friend bool operator>=(const CompoundFile::Property &lhs, const CompoundFile::Property &rhs) {
                return !(lhs < rhs);
            }

            wchar_t name_[32];          // NOLINT
            short nameSize_;         // NOLINT
            unsigned char propertyType_;
            unsigned char nodeColor_;     // Node color (0x43)
            int previousProp_;             // Previous property index (0x44)
            int nextProp_;                 // Next property index (0x48)
            int childProp_;                 // First child property index (0x4c)
            int uk1_;
            int uk2_;
            int uk3_;
            int uk4_;
            int uk5_;
            int seconds1_;     // Seconds component of the created timestamp? (0x64)
            int days1_;         // Days component of the created timestamp? (0x68)
            int seconds2_;     // Seconds component of the modified timestamp? (0x6C)
            int days2_;         // Days component of the modified timestamp? (0x70)
            int startBlock_;
            int size_;
        };
        class PropertyTree {
        public:     // NOLINT
            PropertyTree();
            ~PropertyTree();
            PropertyTree *parent_;
            Property *self_;
            size_t index_;
            vector<PropertyTree *> children_;
        };
        void LoadProperties();
        void SaveProperties();
        int MakeProperty(const wchar_t *path, Property *property);
        PropertyTree *FindProperty(size_t index);
        PropertyTree *FindProperty(const wchar_t *path);
        PropertyTree *FindProperty(PropertyTree *parentTree, wchar_t *name);
        void InsertPropertyTree(PropertyTree *parentTree, Property *property, size_t index);
        void DeletePropertyTree(PropertyTree *tree);
        void UpdateChildrenIndices(PropertyTree *parentTree);
        void IncreasePropertyReferences(PropertyTree *parentTree, size_t index);
        void DecreasePropertyReferences(PropertyTree *parentTree, size_t index);
        PropertyTree *propertyTrees_;
        PropertyTree *currentDirectory_;
        vector<Property *> properties_;
        vector<PropertyTree *> previousDirectories_;
    };
} // YCompoundFiles namespace end       // NOLINT

namespace YExcel {
    using namespace YCompoundFiles;     // NOLINT

    struct CODE {        // NOLINT
        enum {
            FORMULA = 0x0006,         // Token array and the result of a formula cell.
            YEOF = 0x000A,             // End of a record block with leading BOF record.
            CALCCOUNT = 0x000C,         // Maximum number of times the forumlas should be iteratively calculated
            CALCMODE = 0x000D,
            PRECISION = 0x000E,
            REFMODE = 0x000F,         // Method used to show cell addresses in formulas.
            DELTA = 0x0010,             // Maximum change of the result to exit an iteration.
            ITERATION = 0x0011,         // Whether iterations are allowed while calculating recursive formulas.
            PROTECT = 0x0012,         // Whether worksheet or a workbook is protected against modification.
            PASSWORD = 0x0013,
            HEADER = 0x0014,         // Page header string for the current worksheet.
            FOOTER = 0x0015,         // Page footer string for the current worksheet.
            EXTERNSHEET = 0x0017,     // List with indexes to SUPBOOK records
            NAME = 0x0018,             // Name and token array of an internal defined name.
            WINDOWPROTECT = 0x0019,     // Whether the window configuration of the document is protected.
            SELECTION = 0x001D,
            DATEMODE = 0x0022,         // Base date for displaying date values.
            EXTERNNAME = 0x0023,
            LEFTMARGIN = 0x0026,     // Left page margin of the current worksheet.
            RIGHTMARGIN = 0x0027,     // Right page margin of the current worksheet.
            TOPMARGIN = 0x0028,         // Top page margin of the current worksheet.
            BOTTOMMARGIN = 0x0029,     // Bottom page margin of current worksheet
            PRINTHEADERS = 0x002A,
            PRINTGRIDLINES = 0x002B,   // Whether sheet grid lines will be printed.
            FILEPASS = 0x002F,         // Information about the read/write password of the file.
            FONT = 0x0031,             // Information about a used font, including character formatting.
            TABLE = 0x0036,             // Information about a multiple operation table in the sheet.
            CONTINUE = 0x003C,         // Continue from previous record
            WINDOW1 = 0x003D,         // General settings for the workbook global settings.
            BACKUP = 0x0040,         // Make backup of file while saving?
            PANE = 0x0041,             // Position of window panes.
            CODEPAGE = 0x0042,         // Text encoding used to encode byte strings
            DCONREF = 0x0051,
            DEFCOLWIDTH = 0x0055,      // Default column width for columns that do not have a specific width set
            XCT = 0x0059,              // Number of immediately following CRN records.
            CRN = 0x005A,              // Contents of an external cell or cell range.
            FILESHARING = 0x005B,
            WRITEACCESS = 0x005C,      // Name of the user that has saved the file.
            UNCALCED = 0x005E,          // Formulas have not been recalculated before the document was saved.
            SAVERECALC = 0x005F,      // "Recalculate before save" option
            OBJECTPROTECT = 0x0063,      // Whether objects of the current sheet are protected.
            COLINFO = 0x007D,          // Width for a given range of columns
            GUTS = 0x0080,              // Layout of outline symbols.
            WSBOOL = 0x0081,          // 16-bit value with boolean options for the current sheet.
            GRIDSET = 0x0082,          // Whether option to print sheet grid lines has ever been changed.
            HCENTER = 0x0083,          // Sheet is centred horizontally when printed.
            VCENTER = 0x0084,          // Whether sheet is centred vertically when printed.
            BOUNDSHEET = 0x0085,      // Sheet inside of the workbook
            WRITEPROT = 0x0086,          // Whether file is write protected.
            COUNTRY = 0x008C,
            HIDEOBJ = 0x008D,          // Whether and how to show objects in the workbook.
            SORT = 0x0090,              // Last settings from the "Sort" dialogue for each sheet.
            PALETTE = 0x0092,
            SETUP = 0x00A1,              // Page format settings of the current sheet.
            SHRFMLA = 0x00BC,          // Token array of a shared formula.
            MULRK = 0x00BD,
            MULBLANK = 0x00BE,          // Cell range of empty cells. All cells are located in the same row.
            DBCELL = 0x00D7,
            BOOKBOOL = 0x00DA,          // Save values linked from external workbooks records and XCT records?
            SCENPROTECT = 0x00DD,      // Whether scenarios of the current sheet are protected.
            XF = 0x00E0,              // Formatting information for cells, rows, columns or styles.
            MERGEDCELLS = 0x00E5,      // All merged cell ranges of the current sheet.
            SST = 0x00FC,              // List of all strings used anywhere in the workbook.
            LABELSST = 0x00FD,          // Cell that contains a string.
            EXTSST = 0x00FF,
            LABELRANGES = 0x015F,      // Addresses of all row and column label ranges in the current sheet.
            USESELFS = 0x0160,          // Whether formulas in the workbook can use "natural language formulas".
            DSF = 0x0161,              // Whether file contains an addition BIFF5/BIFF7 workbook stream.
            SUPBOOK = 0x01AE,          // URL of an external document and a list of sheet names inside this document.
            CONDFMT = 0x01B0,
            CF = 0x01B1,
            DVAL = 0x01B2,
            HLINK = 0x01B8,
            DV = 0x01BE,
            DIMENSIONS = 0x0200,      // Range address of the used area in the current sheet.
            BLANK = 0x0201,              // Empty cell, contains cell address and formatting information
            NUMBER = 0x0203,          // Cell that contains a floating-point value.
            BOOLERR = 0x0205,          // Error value cell
            STRING = 0x0207,          // Result of a string formula.
            ROW = 0x0208,              // Properties of a single row in the sheet.
            INDEX = 0x020B,
            ARRAY = 0x0221,              // Token array of an array formula
            WINDOW2 = 0x023E,          // Additional settings for the window of a specific worksheet.
            RK = 0x027E,
            STYLE = 0x0293,
            FORMAT = 0x041E,          // Number format.
            SHRFMLA1 = 0x04BC,          // Token array of a shared formula (added).
            QUICKTIP = 0x0800,          // Cell range and text for a tool tip.
            BOF = 0x0809,              // Beginning of file
            SHEETLAYOUT = 0x0862,      // Colour of the tab below the sheet containing the sheet name.
            SHEETPROTECTION = 0x0867,  // Additional options for sheet protection.
            RANGEPROTECTION = 0x0868   // Information about special protected ranges in a protected sheet.
        };
    };

    class Record {     // NOLINT
    public:     // NOLINT
        Record();
        virtual ~Record();
        virtual size_t Read(const char *data);
        virtual size_t Write(char *data);
        virtual size_t DataSize();
        virtual size_t RecordSize();
        short code_;     // NOLINT
        vector<char> data_;
        size_t dataSize_;
        size_t recordSize_;
        vector<size_t> continueIndices_;
    };

    struct BOF : public Record {     // NOLINT
        BOF();
        virtual size_t Read(const char *data);
        virtual size_t Write(char *data);
        short version_;             // NOLINT
        short type_;                // NOLINT
        short buildIdentifier_;     // NOLINT
        short buildYear_;           // NOLINT
        int fileHistoryFlags_;
        int lowestExcelVersion_;
    };

    struct YEOF : public Record {   // NOLINT
        YEOF();
    };

    struct SmallString {            // NOLINT
        SmallString();
        ~SmallString();
        SmallString(const SmallString &s);
        SmallString &operator=(const SmallString &s);
        const SmallString &operator=(const char *str);
        const SmallString &operator=(const wchar_t *str);
        void Reset();
        size_t Read(const char *data);
        size_t Write(char *data);
        size_t DataSize();
        size_t RecordSize();
        size_t StringSize();
        wchar_t *wname_;
        char *name_;
        char unicode_;
    };

    struct LargeString {        // NOLINT
        LargeString();
        ~LargeString();
        LargeString(const LargeString &s);
        LargeString &operator=(const LargeString &s);
        const LargeString &operator=(const char *str);
        const LargeString &operator=(const wchar_t *str);
        void Reset();
        size_t Read(const char *data);
        size_t ContinueRead(const char *data, size_t size);
        size_t Write(char *data);
        size_t DataSize();
        size_t RecordSize();
        size_t StringSize();
        vector<wchar_t> wname_;
        vector<char> name_;
        char unicode_;
        short richtext_;        // NOLINT
        int phonetic_;
    };

    class Workbook {    // NOLINT
    public:             // NOLINT
        Workbook();

    public:     // NOLINT
        struct FileProtection;
        struct CodePage;
        struct DSF;
        struct TabID;
        struct FnGroupCount;
        struct WorkbookProtection;
        struct Window1 : public Record {
            Window1();
            virtual size_t Read(const char *data);
            virtual size_t Write(char *data);
            short horizontalPos_;       // NOLINT
            short verticalPos_;         // NOLINT
            short width_;               // NOLINT
            short height_;              // NOLINT
            short options_;             // NOLINT
            short activeWorksheetIndex_;    // NOLINT
            short firstVisibleTabIndex_;    // NOLINT
            short selectedWorksheetNo_;     // NOLINT
            short worksheetTabBarWidth_;    // NOLINT
        };
        struct Backup;
        struct HideObj;
        struct DateMode;
        struct Precision;
        struct RefreshAll;
        struct BookBool;
        struct Font : public Record {
            Font();
            virtual size_t Read(const char *data);
            virtual size_t Write(char *data);
            virtual size_t DataSize();
            virtual size_t RecordSize();
            short height_;              // NOLINT
            short options_;             // NOLINT
            short colourIndex_;         // NOLINT
            short weight_;              // NOLINT
            short escapementType_;            // NOLINT
            char underlineType_;
            char family_;
            char characterSet_;
            char unused_;
            SmallString name_;
        };
        struct Format;
        struct XF : public Record {
            XF();
            virtual size_t Read(const char *data);
            virtual size_t Write(char *data);
            short fontRecordIndex_;            // NOLINT
            short formatRecordIndex_;            // NOLINT
            short protectionType_;            // NOLINT
            char alignment_;
            char rotation_;
            char textProperties_;
            char usedAttributes_;
            int borderLines_;
            int colour1_;
            short colour2_;            // NOLINT
        };
        struct Style : public Record {
            Style();
            virtual size_t Read(const char *data);
            virtual size_t Write(char *data);
            virtual size_t DataSize();
            virtual size_t RecordSize();
            short XFRecordIndex_;            // NOLINT
            char identifier_;
            char level_;
            LargeString name_;
        };
        struct Palette;
        struct UseSelfs;
        struct BoundSheet : public Record {
            BoundSheet();
            virtual size_t Read(const char *data);
            virtual size_t Write(char *data);
            virtual size_t DataSize();
            virtual size_t RecordSize();
            int BOFpos_;
            char visibility_;
            char type_;
            SmallString name_;
        };
        struct Country;
        struct LinkTable;
        struct SharedStringTable : public Record {
            SharedStringTable();
            virtual size_t Read(const char *data);
            virtual size_t Write(char *data);
            virtual size_t DataSize();
            virtual size_t RecordSize();
            int stringsTotal_;
            int uniqueStringsTotal_;
            vector<LargeString> strings_;
        };
        struct ExtSST : public Record {
            ExtSST();
            virtual size_t Read(const char *data);
            virtual size_t Write(char *data);
            virtual size_t DataSize();
            virtual size_t RecordSize();
            short stringsTotal_;            // NOLINT
            vector<int> streamPos_;
            vector<short> firstStringPos_;            // NOLINT
            vector<short> unused_;            // NOLINT
        };
        size_t Read(const char *data);
        size_t Write(char *data);
        size_t DataSize();
        size_t RecordSize();

        BOF bof_;
        Window1 window1_;
        vector<Font> fonts_;
        vector<XF> XFs_;
        vector<Style> styles_;
        vector<BoundSheet> boundSheets_;
        SharedStringTable sst_;
        ExtSST extSST_;
        YEOF eof_;
    };

    class Worksheet {     // NOLINT
    public:     // NOLINT
        Worksheet();

    public:     // NOLINT
        struct Uncalced;
        struct Index : public Record {
            Index();
            virtual size_t Read(const char *data);
            virtual size_t Write(char *data);
            virtual size_t DataSize();
            virtual size_t RecordSize();
            int unused1_;
            size_t firstUsedRowIndex_;
            size_t firstUnusedRowIndex_;
            int unused2_;
            vector<size_t> DBCellPos_;
        };
        struct CalculationSettings {
            struct CalcCount;
            struct CalcMode;
            struct RefMode;
            struct Delta;
            struct Iteration;
            struct SafeRecalc;
        };
        struct PrintHeaders;
        struct PrintGridlines;
        struct Gridset;
        struct Guts;
        struct DefaultRowHeight;
        struct WSBool;
        struct PageSettings {
            struct Header;
            struct Footer;
            struct HCenter;
            struct VCenter;
            struct LeftMargin;
            struct RightMargin;
            struct TopMargin;
            struct BottomMargin;
            struct PLS;
            struct Setup;
        };
        struct WorksheetProtection;
        struct DefColWidth;
        struct ColInfo;
        struct Sort;
        struct Dimensions : public Record {
            Dimensions();
            virtual size_t Read(const char *data);
            virtual size_t Write(char *data);
            size_t firstUsedRowIndex_;
            size_t lastUsedRowIndexPlusOne_;
            short firstUsedColIndex_;            // NOLINT
            short lastUsedColIndexPlusOne_;            // NOLINT
            short unused_;            // NOLINT
        };
        struct CellTable {
            struct RowBlock {
                struct Row : public Record {
                    Row();
                    virtual size_t Read(const char *data);
                    virtual size_t Write(char *data);
                    short rowIndex_;            // NOLINT
                    short firstCellColIndex_;            // NOLINT
                    short lastCellColIndexPlusOne_;            // NOLINT
                    short height_;            // NOLINT
                    short unused1_;            // NOLINT
                    short unused2_;            // NOLINT
                    int options_;
                };
                struct CellBlock {
                    struct Blank : public Record {
                        Blank();
                        virtual size_t Read(const char *data);
                        virtual size_t Write(char *data);
                        short rowIndex_;            // NOLINT
                        short colIndex_;            // NOLINT
                        short XFRecordIndex_;            // NOLINT
                    };
                    struct BoolErr : public Record {
                        BoolErr();
                        virtual size_t Read(const char *data);
                        virtual size_t Write(char *data);
                        short rowIndex_;            // NOLINT
                        short colIndex_;            // NOLINT
                        short XFRecordIndex_;            // NOLINT
                        char value_;
                        char error_;
                    };
                    struct LabelSST : public Record {
                        LabelSST();
                        virtual size_t Read(const char *data);
                        virtual size_t Write(char *data);
                        short rowIndex_;            // NOLINT
                        short colIndex_;            // NOLINT
                        short XFRecordIndex_;            // NOLINT
                        size_t SSTRecordIndex_;
                    };
                    struct MulBlank : public Record {
                        MulBlank();
                        virtual size_t Read(const char *data);
                        virtual size_t Write(char *data);
                        virtual size_t DataSize();
                        virtual size_t RecordSize();
                        short rowIndex_;            // NOLINT
                        short firstColIndex_;            // NOLINT
                        vector<short> XFRecordIndices_;     // NOLINT
                        short lastColIndex_;            // NOLINT
                    };
                    struct MulRK : public Record {
                        MulRK();
                        virtual size_t Read(const char *data);
                        virtual size_t Write(char *data);
                        virtual size_t DataSize();
                        virtual size_t RecordSize();
                        struct XFRK {
                            XFRK();
                            void Read(const char *data);
                            void Write(char *data);
                            short XFRecordIndex_;            // NOLINT
                            int RKValue_;
                        };     // NOLINT
                        short rowIndex_;            // NOLINT
                        short firstColIndex_;            // NOLINT
                        vector<XFRK> XFRK_;
                        short lastColIndex_;     // NOLINT
                    };     // NOLINT
                    struct Number : public Record {
                        Number();
                        virtual size_t Read(const char *data);
                        virtual size_t Write(char *data);
                        short rowIndex_;            // NOLINT
                        short colIndex_;            // NOLINT
                        short XFRecordIndex_;            // NOLINT
                        double value_;

                    private:     // NOLINT
                        union {      // NOLINT
                            long long intvalue_;     // NOLINT
                            double doublevalue_;         // NOLINT
                        } intdouble_;
                    };
                    struct RK : public Record {
                        RK();
                        virtual size_t Read(const char *data);
                        virtual size_t Write(char *data);
                        short rowIndex_;            // NOLINT
                        short colIndex_;            // NOLINT
                        short XFRecordIndex_;            // NOLINT
                        int value_;
                    };

                    struct Formula : public Record {
                        struct Array : public Record {
                            Array();
                            virtual size_t Read(const char *data);
                            virtual size_t Write(char *data);
                            virtual size_t DataSize();
                            virtual size_t RecordSize();
                            short firstRowIndex_;            // NOLINT
                            short lastRowIndex_;            // NOLINT
                            char firstColIndex_;
                            char lastColIndex_;
                            short options_;            // NOLINT
                            int unused_;
                            vector<char> formula_;
                        };
                        struct ShrFmla : public Record {
                            ShrFmla();
                            virtual size_t Read(const char *data);
                            virtual size_t Write(char *data);
                            virtual size_t DataSize();
                            virtual size_t RecordSize();
                            short firstRowIndex_;            // NOLINT
                            short lastRowIndex_;            // NOLINT
                            char firstColIndex_;
                            char lastColIndex_;
                            short unused_;            // NOLINT
                            vector<char> formula_;
                        };
                        struct ShrFmla1 : public Record {
                            ShrFmla1();
                            virtual size_t Read(const char *data);
                            virtual size_t Write(char *data);
                            virtual size_t DataSize();
                            virtual size_t RecordSize();
                            short firstRowIndex_;            // NOLINT
                            short lastRowIndex_;            // NOLINT
                            char firstColIndex_;
                            char lastColIndex_;
                            short unused_;            // NOLINT
                            vector<char> formula_;
                        };
                        struct Table : public Record {
                            Table();
                            virtual size_t Read(const char *data);
                            virtual size_t Write(char *data);
                            short firstRowIndex_;            // NOLINT
                            short lastRowIndex_;            // NOLINT
                            char firstColIndex_;
                            char lastColIndex_;
                            short options_;            // NOLINT
                            short inputCellRowIndex_;            // NOLINT
                            short inputCellColIndex_;            // NOLINT
                            short inputCellColumnInputRowIndex_;            // NOLINT
                            short inputCellColumnInputColIndex_;            // NOLINT
                        };
                        struct String : public Record {
                            String();
                            virtual size_t Read(const char *data);
                            virtual size_t Write(char *data);
                            virtual size_t DataSize();
                            virtual size_t RecordSize();
                            vector<wchar_t> string_;
                        };

                        Formula();
                        virtual size_t Read(const char *data);
                        virtual size_t Write(char *data);
                        virtual size_t DataSize();
                        virtual size_t RecordSize();
                        short rowIndex_;            // NOLINT
                        short colIndex_;            // NOLINT
                        short XFRecordIndex_;            // NOLINT
                        char result_[8];
                        short options_;            // NOLINT
                        int unused_;
                        vector<char> RPNtoken_;
                        short type_;            // NOLINT

                        Array array_;
                        ShrFmla shrfmla_;
                        ShrFmla1 shrfmla1_;
                        Table table_;
                        String string_;
                    };

                    CellBlock();
                    ~CellBlock();
                    void Reset();
                    size_t Read(const char *data);
                    size_t Write(char *data);
                    size_t DataSize();
                    size_t RecordSize();
                    short RowIndex();            // NOLINT
                    short ColIndex();            // NOLINT
                    short LastColIndex();            // NOLINT
                    short type_;            // NOLINT
                    bool normalType_;

                    Blank blank_;
                    BoolErr boolerr_;
                    LabelSST labelsst_;
                    MulBlank mulblank_;
                    MulRK mulrk_;
                    Number number_;
                    RK rk_;
                    Formula formula_;
                };     // NOLINT
                struct DBCell : public Record {
                    DBCell();
                    virtual size_t Read(const char *data);
                    virtual size_t Write(char *data);
                    virtual size_t DataSize();
                    virtual size_t RecordSize();
                    int firstRowOffset_;
                    vector<short> offsets_;     // NOLINT
                };

                size_t Read(const char *data);
                size_t Write(char *data);
                size_t DataSize();
                size_t RecordSize();

                vector<Row> rows_;
                vector<CellBlock> cellBlocks_;
                DBCell dbcell_;
            };     // NOLINT
            size_t Read(const char *data);
            size_t Write(char *data);
            size_t DataSize();
            size_t RecordSize();

            vector<RowBlock> rowBlocks_;
        };     // NOLINT
        struct Window2 : public Record {     // NOLINT
            Window2();
            virtual size_t Read(const char *data);
            virtual size_t Write(char *data);
            short options_;            // NOLINT
            short firstVisibleRowIndex_;            // NOLINT
            short firstVisibleColIndex_;            // NOLINT
            short gridLineColourIndex_;            // NOLINT
            short unused1_;            // NOLINT
            short magnificationFactorPageBreakPreview_;            // NOLINT
            short magnificationFactorNormalView_;            // NOLINT
            int unused2_;
        };
        struct SCL;
        struct Pane;
        struct Selection;
        struct MergedCells;
        struct LabelRanges;
        struct ConditionalFormattingTable;
        struct HyperlinkTable;
        struct SheetLayout;
        struct SheetProtection;
        struct RangeProtection;

        size_t Read(const char *data);
        size_t Write(char *data);
        size_t DataSize();
        size_t RecordSize();

        BOF bof_;
        Index index_;
        Dimensions dimensions_;
        CellTable cellTable_;
        Window2 window2_;
        YEOF eof_;
    };     // NOLINT

    bool IsRKValueAnInteger(int rkValue);      ///< Returns true if the supplied rk value contains an integer.
    bool IsRKValueADouble(int rkValue);          ///< Returns true if the supplied rk value contains a double.
    double GetDoubleFromRKValue(int rkValue);     // NOLINT
    int GetIntegerFromRKValue(int rkValue);      ///< Convert a rk value to an integer.
    int GetRKValueFromDouble(double value);      ///< Convert a double to a rk value.
    int GetRKValueFromInteger(int value);      ///< Convert an integer to a rk value.
    bool CanStoreAsRKValue(double value);      ///< Returns true if the supplied double can be stored as a rk value.

    // Forward declarations     // NOLINT
    class BasicExcel;     // NOLINT
    class BasicExcelWorksheet;     // NOLINT
    class BasicExcelCell;     // NOLINT

    /*******************************************************************************************************/
    /*                         Actual classes to read and write to Excel files                             */
    /*******************************************************************************************************/
    class BasicExcel {     // NOLINT
    public:     // NOLINT
        BasicExcel();
        BasicExcel(const char *filename);     // NOLINT
        ~BasicExcel();

    public:     // NOLINT
        void New(int sheets = 3);
        bool Load(const char *filename);   ///< Load an Excel workbook from a file.
        bool Save();                       ///< Save current Excel workbook to opened file.
        bool SaveAs(const char *filename);     // NOLINT
        void NewEmptyExcel();

    public:     // NOLINT
        size_t GetTotalWorkSheets();   ///< Total number of Excel worksheets in current Excel workbook.

        BasicExcelWorksheet *GetWorksheet(size_t sheetIndex);
        BasicExcelWorksheet *GetWorksheet(const char *name);
        BasicExcelWorksheet *GetWorksheet(const wchar_t *name);

        BasicExcelWorksheet *AddWorksheet(int sheetIndex = -1);
        BasicExcelWorksheet *AddWorksheet(const char *name, int sheetIndex = -1);
        BasicExcelWorksheet *AddWorksheet(const wchar_t *name, int sheetIndex = -1);

        bool DeleteWorksheet(size_t sheetIndex);
        bool DeleteWorksheet(const char *name);
        bool DeleteWorksheet(const wchar_t *name);

        char *GetAnsiSheetName(size_t sheetIndex);
        wchar_t *GetUnicodeSheetName(size_t sheetIndex);
        bool GetSheetName(size_t sheetIndex, char *name);
        bool GetSheetName(size_t sheetIndex, wchar_t *name);

        bool RenameWorksheet(size_t sheetIndex, const char *to);
        bool RenameWorksheet(size_t sheetIndex, const wchar_t *to);
        bool RenameWorksheet(const char *from, const char *to);
        bool RenameWorksheet(const wchar_t *from, const wchar_t *to);

    private:      // NOLINT
        size_t Read(const char *data, size_t dataSize);
        size_t Write(char *data);
        void AdjustStreamPositions();
        void AdjustBoundSheetBOFPositions();
        void AdjustDBCellPositions();
        void AdjustExtSSTPositions();

        enum {
            WORKBOOK_GLOBALS = 0x0005,
            VISUAL_BASIC_MODULE = 0x0006,
            WORKSHEET = 0x0010,
            CHART = 0x0020
        };

    private:        // NOLINT
        void UpdateYExcelWorksheet();  ///< Update yesheets_ using information from worksheets_.
        void UpdateWorksheets();      ///< Update worksheets_ using information from yesheets_.

    public:     // NOLINT
        CompoundFile file_;                       ///< Compound file handler.
        Workbook workbook_;                       ///< Raw Workbook.
        vector<Worksheet> worksheets_;           ///< Raw Worksheets.
        vector<BasicExcelWorksheet> yesheets_;   ///< Parsed Worksheets.
    };

    class BasicExcelWorksheet {     // NOLINT
        friend class BasicExcel;

    public:     // NOLINT
        BasicExcelWorksheet(BasicExcel *excel, size_t sheetIndex);

    public:                    // NOLINT
        char *GetAnsiSheetName();
        wchar_t *GetUnicodeSheetName();
        bool GetSheetName(char *name);
        bool GetSheetName(wchar_t *name);
        bool Rename(const char *to);
        bool Rename(const wchar_t *to);
        void Print(ostream &os, char delimiter = ',', char textQualifier = '\0');

    public:            // NOLINT
        size_t GetTotalRows();   ///< Total number of rows in current Excel worksheet.
        size_t GetTotalCols();   ///< Total number of columns in current Excel worksheet.

        BasicExcelCell *Cell(size_t row, size_t col);
        bool EraseCell(size_t row, size_t col);

    private:                   // NOLINT
        void UpdateCells();   ///< Update cells using information from BasicExcel.worksheets_.

    private:     // NOLINT
        BasicExcel *excel_;                       ///< Pointer to instance of BasicExcel.
        size_t sheetIndex_;                       ///< Index of worksheet in workbook.
        size_t maxRows_;                       ///< Total number of rows in worksheet.
        size_t maxCols_;                       ///< Total number of columns in worksheet.
        vector<vector<BasicExcelCell>> cells_;   ///< Cells matrix.
    };

    class BasicExcelCell {     // NOLINT
    public:     // NOLINT
        BasicExcelCell();

    public:     // NOLINT
        enum {
            UNDEFINED,
            INT,
            DOUBLE,
            STRING,
            WSTRING
        };
        int Type() const;

        bool Get(int &val) const;        // NOLINT
        bool Get(double &val) const;     // NOLINT
        bool Get(char *str) const;
        bool Get(wchar_t *str) const;
        size_t GetStringLength() const;

        int GetInteger() const;
        double GetDouble() const;
        const char *GetString() const;
        const wchar_t *GetWString() const;

        friend ostream &operator<<(ostream &os, const BasicExcelCell &cell);

        void Set(int val);
        void Set(double val);
        void Set(const char *str);
        void Set(const wchar_t *str);

        void SetInteger(int val);             ///< Set content of current Excel cell to an integer.
        void SetDouble(double val);             ///< Set content of current Excel cell to a double.
        void SetString(const char *str);     ///< Set content of current Excel cell to an ANSI string.
        void SetWString(const wchar_t *str);  ///< Set content of current Excel cell to an Unicode string.

        void EraseContents();   ///< Erase the content of current Excel cell. Set type to UNDEFINED.

    private:     // NOLINT
        int type_;               ///< Type of value stored in current Excel cell. Contains one of the above enums.
        int ival_;               ///< Integer value stored in current Excel cell.
        double dval_;           ///< Double value stored in current Excel cell.
        vector<char> str_;       ///< ANSI string stored in current Excel cell. Include null character.
        vector<wchar_t> wstr_;   ///< Unicode string stored in current Excel cell. Include null character.
    };
}   // Namespace end     // NOLINT
#endif  // HARDWARE_HI3519CAM_POWERCTL_BASICEXCEL_HPP_
